﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using EpidemicSimulator;
using EpidemicSimulator.stopconditions;
using QuickGraph;
using QuickGraph.Serialization;
using System.Xml;
using GraphInformation;
using ComplexNetGeneratorLib;
using EpidemicSimulator.strategies;
using System.Threading;

namespace EpidemicSimulatorTest
{
    class Program
    {
        static void testSimulation()
        {
            SimulationSetup simsetup = new SimulationSetup(new StreamReader(File.OpenRead("terror.graphml.xml")).ReadToEnd(), new StreamReader(File.OpenRead("aids.graphml.xml")).ReadToEnd(), 1, 1);
            Simulation simulation = SimulationFactory.createSimulation(simsetup, "/");
            simulation.addStopCondition(new MaxSimStepNumberStopCondition(100));
            int i = 1;
            do
            {
                simulation.nextSimStep();
                simulation.saveSimulationResultToGraphML("simstep" + i + ".graphml.xml");
                i++;
            } while (simulation.simulationRunning);
        }

        static void Main(string[] args)
        {
            testAsyncSimulation();
            /*var g = new AdjacencyGraph<DiseaseModelNode, DiseaseModelEdge>();

            DiseaseModelNode node1 = new DiseaseModelNode();
            node1.stateName = "Susceptible";
            node1.stateClass = "EpidemicSimulator.states.SusceptibleState";
            node1.nodeColor = "yellow";

            DiseaseModelNode node2 = new DiseaseModelNode();
            node2.stateName = "Infectious";
            node2.stateClass = "EpidemicSimulator.states.InfectiousState";
            node2.nodeColor = "red";

            DiseaseModelEdge edge1 = new DiseaseModelEdge(node1, node2);
            edge1.transitionProbability = 0.3;

            DiseaseModelEdge edge2 = new DiseaseModelEdge(node2, node1);
            edge2.transitionProbability = 0.9;

            g.AddVerticesAndEdge(edge1);
            g.AddVerticesAndEdge(edge2);

            var vertexIdentity = new VertexIdentity<DiseaseModelNode>(DiseaseModelNode.vertexIdentity);
            var edgeIdentity = new EdgeIdentity<DiseaseModelNode, DiseaseModelEdge>(DiseaseModelEdge.edgeIdentity<DiseaseModelNode, DiseaseModelEdge>);

            using (var writer = new XmlTextWriter("sis.graphml", Encoding.UTF8))
            {
                writer.WriteStartDocument();
                g.SerializeToGraphML(writer, vertexIdentity, edgeIdentity);
                //writer.WriteEndDocument();
            }*/

            /*Simulation simulation = SimulationFactory.createSimulation(new StreamReader(File.OpenRead("terror.graphml.xml")).ReadToEnd(), new StreamReader(File.OpenRead("sis.graphml.xml")).ReadToEnd(), "/");
            simulation.addStopCondition(new MaxSimStepNumberStopCondition(100));
            simulation.runSimulation();
            simulation.saveSimulationResultToGraphML("test1.graphml");
            
            var g = simulation.getSimulationResultForSilverlight();
            var vertexIdentity = new VertexIdentity<GraphElement>(vertexIdentityFunc);
            var edgeIdentity = new EdgeIdentity<GraphElement, Edge<GraphElement>>(edgeIdentityFunc<GraphElement, Edge<GraphElement>>);

            using (var writer = new XmlTextWriter("test2.graphml", Encoding.UTF8))
            {
                writer.WriteStartDocument();
                g.SerializeToGraphML(writer, vertexIdentity, edgeIdentity);
            }*/
            //simulation.reset();

            /*Console.WriteLine("Podaj liczbe wezlow sieci:");
            int n = int.Parse(Console.ReadLine());

            ComplexNetGenerator generator = new ComplexNetGenerator();
            ComplexNet network = generator.generateScaleFree(n, 1, 1);
            StreamWriter writer = new StreamWriter("ScaleFree.graphml.xml", false, Encoding.UTF8);
            network.saveAsGraphML(writer);
            writer.Close();

            StreamWriter output1 = new StreamWriter("output1.txt", false, Encoding.UTF8);
            SimulationSetup simsetup = new SimulationSetup(new StreamReader(File.OpenRead("ScaleFree.graphml.xml")).ReadToEnd(), new StreamReader(File.OpenRead("ebola.graphml.xml")).ReadToEnd(), 500);
            simsetup.addStopCondition(new MaxSimStepNumberStopCondition(1000));
            simsetup.addStopCondition(new NoInfectedNodesStopCondition());
            PersentageStateChangePlan infectionPlan = new PersentageStateChangePlan(10, new RandomInfectionStrategy());
            simsetup.addStateChangePlan(infectionPlan);
            Simulation simulation = SimulationFactory.createSimulation(simsetup, "/");

            generateReports(simulation, output1);

            StreamWriter output2 = new StreamWriter("output2.txt", false, Encoding.UTF8);
            SimulationSetup simsetup2 = new SimulationSetup(new StreamReader(File.OpenRead("ScaleFree.graphml.xml")).ReadToEnd(), new StreamReader(File.OpenRead("ebola.graphml.xml")).ReadToEnd(), 500);
            simsetup2.addStopCondition(new MaxSimStepNumberStopCondition(1000));
            simsetup2.addStopCondition(new NoInfectedNodesStopCondition());
            PersentageStateChangePlan infectionPlan2 = new PersentageStateChangePlan(10, new DegreeCentralityInfectionStrategy());
            simsetup2.addStateChangePlan(infectionPlan2);
            Simulation simulation2 = SimulationFactory.createSimulation(simsetup2, "/");

            generateReports(simulation2, output2);


            StreamWriter output3 = new StreamWriter("output3.txt", false, Encoding.UTF8);
            SimulationSetup simsetup3 = new SimulationSetup(new StreamReader(File.OpenRead("ScaleFree.graphml.xml")).ReadToEnd(), new StreamReader(File.OpenRead("ebola.graphml.xml")).ReadToEnd(), 500);
            simsetup3.addStopCondition(new MaxSimStepNumberStopCondition(1000));
            simsetup3.addStopCondition(new NoInfectedNodesStopCondition());
            PersentageStateChangePlan infectionPlan3 = new PersentageStateChangePlan(10, new BetweennessCentralityInfectionStrategy());
            simsetup3.addStateChangePlan(infectionPlan3);
            Simulation simulation3 = SimulationFactory.createSimulation(simsetup3, "/");

            generateReports(simulation3, output3);*/

            //---------------------------------------------------------------------------------------
            /*
            StreamWriter output4 = new StreamWriter("output4.txt", false, Encoding.UTF8);
            SimulationSetup simsetup4 = new SimulationSetup(new StreamReader(File.OpenRead("ScaleFree.graphml.xml")).ReadToEnd(), new StreamReader(File.OpenRead("ebola.graphml.xml")).ReadToEnd(), 5);
            simsetup4.addStopCondition(new MaxSimStepNumberStopCondition(1000));
            simsetup4.addStopCondition(new NoInfectedNodesStopCondition());
            PersentageStateChangePlan infectionPlan4 = new PersentageStateChangePlan(1, new RandomInfectionStrategy());
            PersentageStateChangePlan inoculationPlan4 = new PersentageStateChangePlan(1, new DegreeCentralityInoculationStrategy());
            simsetup4.addStateChangePlan(inoculationPlan4);
            simsetup4.addStateChangePlan(infectionPlan4);
            Simulation simulation4 = SimulationFactory.createSimulation(simsetup4, "/");

            generateReports(simulation4, output4);

            StreamWriter output5 = new StreamWriter("output5.txt", false, Encoding.UTF8);
            SimulationSetup simsetup5 = new SimulationSetup(new StreamReader(File.OpenRead("ScaleFree.graphml.xml")).ReadToEnd(), new StreamReader(File.OpenRead("ebola.graphml.xml")).ReadToEnd(), 5);
            simsetup5.addStopCondition(new MaxSimStepNumberStopCondition(1000));
            simsetup5.addStopCondition(new NoInfectedNodesStopCondition());
            PersentageStateChangePlan infectionPlan5 = new PersentageStateChangePlan(1, new DegreeCentralityInfectionStrategy());
            PersentageStateChangePlan inoculationPlan5 = new PersentageStateChangePlan(1, new DegreeCentralityInoculationStrategy());
            simsetup5.addStateChangePlan(inoculationPlan5);
            simsetup5.addStateChangePlan(infectionPlan5);
            Simulation simulation5 = SimulationFactory.createSimulation(simsetup5, "/");

            generateReports(simulation5, output5);


            StreamWriter output6 = new StreamWriter("output6.txt", false, Encoding.UTF8);
            SimulationSetup simsetup6 = new SimulationSetup(new StreamReader(File.OpenRead("ScaleFree.graphml.xml")).ReadToEnd(), new StreamReader(File.OpenRead("ebola.graphml.xml")).ReadToEnd(), 5);
            simsetup6.addStopCondition(new MaxSimStepNumberStopCondition(1000));
            simsetup6.addStopCondition(new NoInfectedNodesStopCondition());
            PersentageStateChangePlan infectionPlan6 = new PersentageStateChangePlan(1, new BetweennessCentralityInfectionStrategy());
            PersentageStateChangePlan inoculationPlan6 = new PersentageStateChangePlan(1, new DegreeCentralityInoculationStrategy());
            simsetup6.addStateChangePlan(inoculationPlan6);
            simsetup6.addStateChangePlan(infectionPlan6);
            Simulation simulation6 = SimulationFactory.createSimulation(simsetup6, "/");

            generateReports(simulation6, output6);

            //---------------------------------------------------------------------------------------

            StreamWriter output7 = new StreamWriter("output7.txt", false, Encoding.UTF8);
            SimulationSetup simsetup7 = new SimulationSetup(new StreamReader(File.OpenRead("ScaleFree.graphml.xml")).ReadToEnd(), new StreamReader(File.OpenRead("ebola.graphml.xml")).ReadToEnd(), 5);
            simsetup7.addStopCondition(new MaxSimStepNumberStopCondition(1000));
            simsetup7.addStopCondition(new NoInfectedNodesStopCondition());
            PersentageStateChangePlan infectionPlan7 = new PersentageStateChangePlan(1, new RandomInfectionStrategy());
            PersentageStateChangePlan inoculationPlan7 = new PersentageStateChangePlan(1, new BetweennessCentralityInoculationStrategy());
            simsetup7.addStateChangePlan(inoculationPlan7);
            simsetup7.addStateChangePlan(infectionPlan7);
            Simulation simulation7 = SimulationFactory.createSimulation(simsetup7, "/");

            generateReports(simulation7, output7);

            StreamWriter output8 = new StreamWriter("output8.txt", false, Encoding.UTF8);
            SimulationSetup simsetup8 = new SimulationSetup(new StreamReader(File.OpenRead("ScaleFree.graphml.xml")).ReadToEnd(), new StreamReader(File.OpenRead("ebola.graphml.xml")).ReadToEnd(), 5);
            simsetup8.addStopCondition(new MaxSimStepNumberStopCondition(1000));
            simsetup8.addStopCondition(new NoInfectedNodesStopCondition());
            PersentageStateChangePlan infectionPlan8 = new PersentageStateChangePlan(1, new DegreeCentralityInfectionStrategy());
            PersentageStateChangePlan inoculationPlan8 = new PersentageStateChangePlan(1, new BetweennessCentralityInoculationStrategy());
            simsetup8.addStateChangePlan(inoculationPlan8);
            simsetup8.addStateChangePlan(infectionPlan8);
            Simulation simulation8 = SimulationFactory.createSimulation(simsetup8, "/");

            generateReports(simulation8, output8);


            StreamWriter output9 = new StreamWriter("output9.txt", false, Encoding.UTF8);
            SimulationSetup simsetup9 = new SimulationSetup(new StreamReader(File.OpenRead("ScaleFree.graphml.xml")).ReadToEnd(), new StreamReader(File.OpenRead("ebola.graphml.xml")).ReadToEnd(), 5);
            simsetup9.addStopCondition(new MaxSimStepNumberStopCondition(1000));
            simsetup9.addStopCondition(new NoInfectedNodesStopCondition());
            PersentageStateChangePlan infectionPlan9 = new PersentageStateChangePlan(1, new BetweennessCentralityInfectionStrategy());
            PersentageStateChangePlan inoculationPlan9 = new PersentageStateChangePlan(1, new BetweennessCentralityInoculationStrategy());
            simsetup9.addStateChangePlan(inoculationPlan9);
            simsetup9.addStateChangePlan(infectionPlan9);
            Simulation simulation9 = SimulationFactory.createSimulation(simsetup9, "/");

            generateReports(simulation9, output9);
            */
        }

        public static string vertexIdentityFunc<TVertex>(TVertex v)
        {
            return v.ToString();
        }

        public static string edgeIdentityFunc<TVertex, TEdge>(TEdge edge)
            where TEdge : EdgeWithAttributes.EdgeWithAttributes<GraphElement>
        {
            return edge.Source.Id.ToString() + "-" + edge.Target.Id.ToString();
        }

        public static void generateReports(Simulation simulation, StreamWriter output)
        {
            

            output.Write("Krok symulacji");
            foreach (DiseaseModelNode diseaseState in simulation.diseaseModelGraph.Vertices)
            {
                output.Write(";" + diseaseState.stateName);
            }
            output.WriteLine();

            var socialNetwork = simulation.socialNetwork;

            output.Write(0);
            foreach (DiseaseModelNode diseaseState in simulation.diseaseModelGraph.Vertices)
            {
                int counter = 0;
                foreach (SocialNetworkNode node in socialNetwork.Vertices)
                {
                    if (node.state.stateNode.stateName == diseaseState.stateName)
                    {
                        counter++;
                    }
                }
                output.Write(";" + counter.ToString());
            }
            output.WriteLine();

            int i = 1;
            do
            {
                simulation.nextSimStep();
                socialNetwork = simulation.getSimulationResult();
                output.Write(i);
                foreach (DiseaseModelNode diseaseState in simulation.diseaseModelGraph.Vertices)
                {
                    int counter = 0;
                    foreach (SocialNetworkNode node in socialNetwork.Vertices)
                    {
                        if (node.state.stateNode.stateName == diseaseState.stateName)
                        {
                            counter++;
                        }
                    }
                    output.Write(";"+counter.ToString());
                }
                output.WriteLine();
                i++;
            } while (simulation.simulationRunning);
            output.Close();
        }

        private static void testAsyncSimulation()
        {
            ComplexNetGenerator generator = new ComplexNetGenerator();
            ComplexNet network = generator.generateScaleFree(100, 1, 1);
            StreamWriter writer = new StreamWriter("ScaleFree.graphml.xml", false, Encoding.UTF8);
            network.saveAsGraphML(writer);
            writer.Close();

            StreamWriter output = new StreamWriter("output.txt", false, Encoding.UTF8);
            SimulationSetup simsetup = new SimulationSetup(new StreamReader(File.OpenRead("ScaleFree.graphml.xml")).ReadToEnd(), new StreamReader(File.OpenRead("ebola.graphml.xml")).ReadToEnd(), 500, 1);
            simsetup.addStopCondition(new MaxSimStepNumberStopCondition(1000));
            simsetup.addStopCondition(new NoInfectedNodesStopCondition());
            PersentageStateChangePlan infectionPlan = new PersentageStateChangePlan(10, new RandomInfectionStrategy());
            simsetup.addStateChangePlan(infectionPlan);

            SimulationManager simManager = new SimulationManager(simsetup, 20, "/");
            simManager.runSimulationAsync();

            while (true)
            {
                Thread.Sleep(100);
                ExperimentState[] exStates = simManager.getExperimentState();
                bool allStopped = true;
                foreach (ExperimentState exState in exStates)
                {
                    if (exState.running) allStopped = false;
                }
                if (allStopped) break;
            }

            EpidemicSimulator.reports.SimulationSimpleReport report = simManager.getSimulationReport();
            output.WriteLine("simTime = " + report.simTime);
            output.WriteLine();
            foreach(var dataSet in report.dataSets)
            {
                output.WriteLine(dataSet.label + " " + dataSet.color + " " + dataSet.value.ToString());
            }
            output.Close();
        }
    }
}
